package com.gtc.zsk.blackfilter;

import cn.dev33.satoken.stp.StpUtil;
import com.gtc.zsk.common.ErrorCode;
import com.gtc.zsk.exception.BusinessException;
import com.gtc.zsk.manager.MailManager;
import com.gtc.zsk.manager.RedisLimiterManager;
import com.gtc.zsk.model.entity.User;
import com.gtc.zsk.model.enums.UserRoleEnum;
import com.gtc.zsk.service.UserService;
import com.gtc.zsk.utils.NetUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

import static com.gtc.zsk.constant.UserConstant.USER_LOGIN_STATE;

@Slf4j
@WebFilter(urlPatterns = "/*", filterName = "blackIpFilter")
public class BlackIpFilter implements Filter {

    @Resource
    private MailManager mailManager;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;
    @Resource
    private RedisLimiterManager redisLimiterManager;


    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        String ipAddress = NetUtils.getIpAddress((HttpServletRequest) servletRequest);
        //记录ip日志
        recordRequestInfo(ipAddress);
        if (BlackIpUtils.isBlackIp(ipAddress)) {
            servletResponse.setContentType("text/json;charset=UTF-8");
            servletResponse.getWriter().write("{\"errorCode\":\"-1\",\"errorMsg\":\"黑名单IP，禁止访问，详情请联系管理员\"}");
            return;
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    private void recordRequestInfo(String ip) {
        if ("81.68.92.140".equals(ip))
            return;
        try {
            redisLimiterManager.doRateLimit("rate_" + ip);
        } catch (BusinessException e) {
            Object userObj = StpUtil.getSession().get(USER_LOGIN_STATE);
            User user = (User) userObj;
            // 如果没登录 或者 登陆了但不是管理员，超过限制频率的话，才会发邮箱通知
            if (user == null || !UserRoleEnum.ADMIN.getValue().equals(user.getUserRole())){
                mailManager.sendMessage("用户访问过快警告！", "ip: " + ip, "1615337902@qq.com");
                throw e;
            }
        }
        Object loginId = StpUtil.getLoginIdDefaultNull();
        redisTemplate.opsForHash().increment("operations",ip,1);
        if (loginId != null)
            redisTemplate.opsForHash().put("operations", loginId.toString(), ip);
    }

}
